// MainWindow.cs
// 
// Copyright (C) 2008 Jean-André Santoni
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

using System;
using System.IO;
using System.Collections;
using System.Reflection;
using Gtk;
using Astrognome;
using Cairo;
using ChartStyle;

public partial class MainWindow: Gtk.Window
{
	public Config Config;
	string appdir = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName);
	
	public MainWindow (): base (Gtk.WindowType.Toplevel)
	{
		Build ();
		try
		{
			Config = Serializer.DeSerializeConfig();
		}
		catch
		{
			Config = new Config();
			Config.ChartStyle = "DefaultStyle";
		}
		UpdateActions();
	}
	
	public Chart CurrentChart
	{
		get
		{
			return ((ChartDrawingArea) ((AspectFrame) ((HPaned) notebook.CurrentPageWidget).Child1).Child).Chart;
		}
	}
	
	protected virtual void OnNewActionActivated (object sender, System.EventArgs e)
	{
		NewDialog nd = new NewDialog(this);
		nd.Run();
		nd.Destroy();
	}
	
	public void AddPage (Chart chart)
	{
		Image img = new Image();
		img.SetFromStock("gtk-close", IconSize.Menu);
		
		Button btn = new Button();
		btn.Image = img;
		btn.Relief = ReliefStyle.None;
		btn.Name = "tab-close-button";
		
		Gtk.Rc.ParseString("style \"tab-close-button-style\" { \n GtkWidget::focus-padding = 0 \n GtkWidget::focus-line-width = 0 \n xthickness = 0 \n ythickness = 0 \n } \n widget \"*.tab-close-button\" style \"tab-close-button-style\" \n");
		
		HBox hbx = new HBox();
		hbx.PackStart(new Label(chart.Name), true, true, 1);
		hbx.PackEnd(btn, true, true, 1);
		hbx.ShowAll();
		
		ChartDrawingArea cda = new ChartDrawingArea(this, chart);
		
		AspectFrame af = new AspectFrame(null, 0.5F, 0.5F, 1F, false);
		af.Shadow = ShadowType.In;
		af.Add(cda);
		
		HPaned hp = new HPaned();
		hp.Pack1(af, true, true);
		ChartControl cc = new ChartControl(this, chart);
		hp.Pack2(cc, false, false);
		
		notebook.AppendPage(hp, hbx);
		notebook.SetTabReorderable(hp, true);
		notebook.CurrentPage = notebook.PageNum(hp);
		notebook.ShowAll();
		
		btn.Clicked += delegate(object sender, EventArgs e) { OnCloseButtonClicked(sender, e, chart, hp); }; 
		
		UpdateActions();
	}

	protected virtual void OnOpenActionActivated (object sender, System.EventArgs e)
	{
		FileChooserDialog fcd = new FileChooserDialog("Choose a chart to open", this, FileChooserAction.Open, "Cancel",ResponseType.Cancel, "Open",ResponseType.Accept);

		fcd.Filter = new FileFilter();
		fcd.Filter.Name = "Chart File";
		fcd.Filter.AddPattern("*.chart");
		
		if (fcd.Run() == (int)ResponseType.Accept)
		{
			Chart chart = Serializer.DeSerializeChart(fcd.Filename);
			AddPage(chart);
		}
		
		fcd.Destroy();
		UpdateActions();
	}
	
	protected virtual void OnSaveActionActivated (object sender, System.EventArgs e)
	{
		if (CurrentChart.FileName == "")
		{
			OnSaveAs(CurrentChart);
		}
		else
		{
			Serializer.SerializeChart(CurrentChart.FileName, CurrentChart);
			CurrentChart.Saved = true;
		}
	}
	
	protected virtual void OnSaveAsActionActivated (object sender, System.EventArgs e)
	{
		OnSaveAs(CurrentChart);
	}
	
	protected void OnSaveAs (Chart chart)
	{
		string filename = chart.Saved ? chart.FileName : chart.Name + ".chart";
		
		FileChooserDialog fcd = new FileChooserDialog("Save as...", this, FileChooserAction.Save, "Cancel",ResponseType.Cancel, "Save",ResponseType.Accept);
		fcd.CurrentName = filename;
		
		fcd.Filter = new FileFilter();
		fcd.Filter.Name = "Chart File";
		fcd.Filter.AddPattern("*.chart");
		
		if (fcd.Run() == (int)ResponseType.Accept) 
		{
			FileInfo fi = new FileInfo(fcd.Filename);
			if (fi.Exists)
			{
				MessageDialog dlg = new MessageDialog(this, DialogFlags.Modal, MessageType.Question, ButtonsType.YesNo, "");
				dlg.Markup = "File « " + fcd.Filename + " »\nalready exists. Overwrite?";
				if (dlg.Run() == (int) ResponseType.Yes)
				{
					chart.FileName = fcd.Filename;
					Serializer.SerializeChart(fcd.Filename, chart);
					chart.Saved = true;
				}
				dlg.Destroy();
			}
			else
			{
				chart.FileName = fcd.Filename;
				Serializer.SerializeChart(fcd.Filename, chart);
				chart.Saved = true;
			}
		}

		fcd.Destroy();
		UpdateActions();
	}
	
	protected virtual void OnRefreshActionActivated (object sender, System.EventArgs e)
	{
		OnChartRefresh();
	}
	
	protected virtual void OnCloseActionActivated (object sender, System.EventArgs e)
	{
		OnClose(CurrentChart, (HPaned) notebook.CurrentPageWidget);
	}
	
	protected void OnCloseButtonClicked (object sender, System.EventArgs e, Chart chart, HPaned hp)
	{
		OnClose(chart, hp);
	}
	
	protected void OnClose (Chart chart, HPaned hp)
	{
		if (chart.Saved)
		{
			notebook.Remove(hp);
		}
		else
		{
			MessageDialog dlg = new MessageDialog(this, DialogFlags.Modal, MessageType.Warning, ButtonsType.None, "");
			dlg.Markup = "<b>Save the changes to document\n« " + chart.Name + ".chart » before closing?</b>";
			dlg.SecondaryText = "If you don't save, changes will be permanently lost.";
			dlg.AddButton("_Close without saving", ResponseType.No);
			dlg.AddButton(Stock.Cancel, ResponseType.Cancel);
			dlg.AddButton(Stock.SaveAs, ResponseType.Ok);
			int result = dlg.Run();
			switch(result)
			{
				case (int) ResponseType.No:
					notebook.Remove(hp);
					break;
				
				case (int) ResponseType.Ok:
					OnSaveAs(chart);
					break;
			}
			dlg.Destroy();
		}
		UpdateActions();
	}

	protected virtual void OnNotebookSwitchPage (object o, Gtk.SwitchPageArgs args)
	{
		UpdateActions();
	}
	
	protected void UpdateActions ()
	{
		if (notebook.NPages > 0)
		{
			SaveAction.Sensitive = ! CurrentChart.Saved;
			SaveAsAction.Sensitive = true;
			ExportAsSVGAction.Sensitive = true;
			PrintPreviewAction.Sensitive = true;
			PrintAction.Sensitive = true;
			RefreshAction.Sensitive = true;
			CloseAction.Sensitive = true;
		}
		else
		{
			SaveAction.Sensitive = false;
			SaveAsAction.Sensitive = false;
			ExportAsSVGAction.Sensitive = false;
			PrintPreviewAction.Sensitive = false;
			PrintAction.Sensitive = false;
			RefreshAction.Sensitive = false;
			CloseAction.Sensitive = false;
		}
	}
	
	protected virtual void OnAboutActionActivated (object sender, System.EventArgs e)
	{
		AboutDialog ad = new AboutDialog();
		ad.IconName = Stock.About;
		ad.Logo = new Gdk.Pixbuf(appdir + "/Astrognome.svg");
		ad.Version = "0.1.1";
		ad.Comments = "A simple natal chart drawing program\nwritten in GTK#.";
		ad.Copyright = "Copyright (C) 2008 Jean-André Santoni";
		ad.Website = "http://astrognome.kivutar.fr/";
		ad.Authors = ad.Artists = new string[] {"Jean-André Santoni <jean.andre.santoni@gmail.com>"};
		ad.License = "Astrognome is free software: you can redistribute it and/or modify\n";
		ad.License += "it under the terms of the GNU General Public License as published by\n";
		ad.License += "the Free Software Foundation, either version 3 of the License, or\n";
		ad.License += "(at your option) any later version.\n";
		ad.License += "\n";
		ad.License += "This program is distributed in the hope that it will be useful,\n";
		ad.License += "but WITHOUT ANY WARRANTY; without even the implied warranty of\n";
		ad.License += "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n";
		ad.License += "GNU General Public License for more details.\n";
		ad.License += "\n";
		ad.License += "You should have received a copy of the GNU General Public License\n";
		ad.License += "along with this program.  If not, see http://www.gnu.org/licenses/.\n";
		ad.SkipPagerHint = true;
		ad.SkipTaskbarHint = true;
		ad.Run();
		ad.Destroy();
	}

	protected virtual void OnQuitActionActivated (object sender, System.EventArgs e)
	{
		while (notebook.NPages > 0)
		{
			OnCloseActionActivated(sender, e);
		}
		
		Application.Quit ();
	}
	
	protected void OnDeleteEvent (object sender, DeleteEventArgs a)
	{
		OnQuitActionActivated(sender, new EventArgs());
		a.RetVal = true;
	}
	
	public void OnChartRefresh ()
	{
		try
		{
			ChartDrawingArea cda = (ChartDrawingArea) ((AspectFrame) ((HPaned) notebook.CurrentPageWidget).Child1).Child;
			cda.UpdateChartInfo();
			cda.Hide();
			cda.Show();
		}
		catch
		{
			notebook.Hide();
			notebook.Show();
		}
	}

	protected virtual void OnPreferencesActionActivated (object sender, System.EventArgs e)
	{
		PreferencesDialog pd = new PreferencesDialog(this);
		pd.Run();
		pd.Destroy();
	}

	protected virtual void OnPrintActionActivated (object sender, System.EventArgs e)
	{	
		PrintOperation po = new PrintOperation();
		po.ShowProgress = true;
		po.NPages = 1;
		po.DrawPage += DrawPage;
		po.Run(PrintOperationAction.PrintDialog, this);
	}

	protected virtual void OnExportAsSVGActionActivated (object sender, System.EventArgs e)
	{
		FileChooserDialog fcd = new FileChooserDialog("Export as SVG", this, FileChooserAction.Save, "Cancel",ResponseType.Cancel, "Save",ResponseType.Accept);
		
		fcd.Filter = new FileFilter();
		fcd.Filter.Name = "Plain SVG";
		fcd.Filter.AddPattern("*.svg");
		
		if (fcd.Run() == (int)ResponseType.Accept) 
		{
			FileInfo fi = new FileInfo(fcd.Filename);
			if (fi.Exists)
			{
				MessageDialog dlg = new MessageDialog(this, DialogFlags.Modal, MessageType.Question, ButtonsType.YesNo, "");
				dlg.Markup = "File « " + fcd.Filename + " »\nalready exists. Overwrite?";
				if (dlg.Run() == (int) ResponseType.Yes)
				{
					SvgSurface svg = new SvgSurface(fcd.Filename, 744.09, 1052.36);
					Context ctx = new Context(svg);	
					A4.Draw(ctx, CurrentChart, Config, 744.09, 1052.36);
					svg.Finish();
				}
				dlg.Destroy();
			}
			else
			{
				SvgSurface svg = new SvgSurface(fcd.Filename, 744.09, 1052.36);
				Context ctx = new Context(svg);	
				A4.Draw(ctx, CurrentChart, Config, 744.09, 1052.36);
				svg.Finish();
			}
		}

		fcd.Destroy();
	}
	
	protected virtual void DrawPage (object sender, DrawPageArgs e)
	{
		Context ctx = e.Context.CairoContext;
		A4.Draw(ctx, CurrentChart, Config, e.Context.Width, e.Context.Height);
	}

	protected virtual void OnPrintPreviewActionActivated (object sender, System.EventArgs e)
	{
		PrintOperation po = new PrintOperation();
		po.ShowProgress = true;
		po.NPages = 1;
		po.DrawPage += DrawPage;
		po.Run(PrintOperationAction.Preview, this);
	}
}